package dsk.demo.product.config;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import dsk.demo.product.dao.GWeekMessageDao;
import dsk.demo.product.entity.gupiao.GWeekMessage;
import dsk.demo.product.entity.gupiao.GWeekPrice;
import dsk.demo.product.util.QiyeVxUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Component
public class 判断低估 {

    @Autowired
    private QiyeVxUtil qiyeVxUtil;
    @Autowired
    private GWeekMessageDao gWeekMessageDao;

    private static List<String> PUSH_LIST = Arrays.asList(new String[]{"DaiShiKun", "ChenDong"});
//
//    private static Map<String, String> GUPIAO_MAP = new HashMap<>();
//
//    static {
//        GUPIAO_MAP.put("sh512890", "红利低波"); //
//        GUPIAO_MAP.put("sh516100", "金融科技"); //
//        GUPIAO_MAP.put("sh588060", "科创50ETF"); //
//        GUPIAO_MAP.put("sz159813", "半导体"); //
//        GUPIAO_MAP.put("sz159928", "消费"); //
//        GUPIAO_MAP.put("sh512010", "医药"); //
//        GUPIAO_MAP.put("sh515700", "新能源汽车产业"); //
//        GUPIAO_MAP.put("sh562500", "机器人"); //
//        GUPIAO_MAP.put("sh515020", "银行"); //
//    }

    // 每个交易日 10点 3分处理这些股票
    @Scheduled(cron = "0 3 10 * * MON-FRI")
    public void 定时任务() {
        List<GWeekMessage> gWeekMessages = gWeekMessageDao.selectList(Wrappers.lambdaQuery());
        DateTime week = DateUtil.beginOfWeek(new Date());
        for (GWeekMessage gWeekMessage : gWeekMessages) {
            if (gWeekMessage.getLastMessageDate() == null || week.compareTo(gWeekMessage.getLastMessageDate()) != 0) {
                // 本周 还没有提示, 在查询是否低估
                panduanIsChaomai(gWeekMessage);
                try {
                    Thread.sleep(4000);
                } catch (Exception e) {
                }
            }

        }
    }

    // sh512890 - 红利低波
    // 判断某个ETF是否超卖
    public void panduanIsChaomai(GWeekMessage weekMessage) {

        String ret = HttpUtil.get("https://proxy.finance.qq.com/ifzqgtimg/appstock/app/newfqkline/get?param=" + weekMessage.getGupiaoCode() + ",week,,,320,qfq&type=qfq&_var=kline_weekqfq");
        JSONObject object = JSONUtil.parseObj(ret.split("=")[1]);
        JSONObject data = object.getJSONObject("data").getJSONObject(weekMessage.getGupiaoCode());

        JSONArray jsonArray = null;
        if (data.containsKey("qfqweek")) {
            jsonArray = data.getJSONArray("qfqweek");
        } else if (data.containsKey("week")) {
            jsonArray = data.getJSONArray("week");
        }

        if (CollectionUtil.isEmpty(jsonArray)) {
            return;
        }
        // 周线数据
        List<GWeekPrice> gWeekPrices = copyList(jsonArray);
        // 用当周最低价去计算最低 rsi
        GWeekPrice gWeekPrice1 = gWeekPrices.get(gWeekPrices.size() - 1);
        gWeekPrice1.setThsCloseWFund(gWeekPrice1.getThsLowWFund());

        // 计算rsi数据
        dealRsi(gWeekPrices);

        GWeekPrice lastData = gWeekPrices.get(gWeekPrices.size() - 1);
        log.info("股票:[{}], 最新一天的数据为:[{}]", weekMessage.getGupiaoName(), JSONUtil.toJsonStr(lastData, new JSONConfig().setDateFormat("yyyy-MM-dd")));

        if (gWeekPrices.get(gWeekPrices.size() - 1).getRsi6().compareTo(new BigDecimal("35")) < 0) {
            log.info("股票:" + weekMessage.getGupiaoName() + "当前rsi值:" + gWeekPrices.get(gWeekPrices.size() - 1).getRsi6()
                    + ",  正处于低估区间, 请关注");
            DateTime week = DateUtil.beginOfWeek(new Date());
            // 更新数据
            weekMessage.setLastMessageDate(week);
            gWeekMessageDao.updateById(weekMessage);
            // 发送企业微信消息
            qiyeVxUtil.sendMail("股票:" + weekMessage.getGupiaoName() + "当前rsi值:" + gWeekPrices.get(gWeekPrices.size() - 1).getRsi6()
                            + ",  正处于低估区间, 请关注"
                    , PUSH_LIST);
        }

    }


    public void dealRsi(List<GWeekPrice> gWeekPrices) {
        for (int i = 6; i <= gWeekPrices.size(); i++) {
            List<GWeekPrice> sub = CollectionUtil.sub(gWeekPrices, i - 6, i);
            if (i == 6) {
                // 6日平均涨幅/ 6日平均跌幅
                List<GWeekPrice> zhangfu = sub.stream().filter(item -> item.getThsChgRatioWFund().compareTo(BigDecimal.ZERO) > 0).collect(Collectors.toList());
                List<GWeekPrice> diefu = sub.stream().filter(item -> item.getThsChgRatioWFund().compareTo(BigDecimal.ZERO) < 0).collect(Collectors.toList());

                BigDecimal AU = BigDecimal.ZERO;
                if (zhangfu.size() > 0) {
                    AU = zhangfu.stream().map(GWeekPrice::getThsChgRatioWFund).reduce(BigDecimal.ZERO, BigDecimal::add)
                            .divide(new BigDecimal(6), 4, RoundingMode.HALF_UP).setScale(4, RoundingMode.HALF_UP);
                }

                BigDecimal DU = BigDecimal.ZERO;
                if (zhangfu.size() > 0) {
                    DU = diefu.stream().map(GWeekPrice::getThsChgRatioWFund).reduce(BigDecimal.ZERO, BigDecimal::add)
                            .divide(new BigDecimal(6), 4, RoundingMode.HALF_UP).setScale(4, RoundingMode.HALF_UP).abs();
                }
                BigDecimal RSI = getRSI(AU, DU);
                sub.get(5).setRsi6(RSI);
                sub.get(5).setRsi6zhangfu(AU);
                sub.get(5).setRsi6diefu(DU);
            } else {
                // 平滑移动平均法
                BigDecimal X = max(sub.get(5).getThsCloseWFund().subtract(sub.get(4).getThsCloseWFund()), BigDecimal.ZERO);
                BigDecimal AU = X.add(sub.get(4).getRsi6zhangfu().multiply(new BigDecimal(5))).divide(new BigDecimal(6), 4, RoundingMode.HALF_UP);

                BigDecimal X2 = min(sub.get(5).getThsCloseWFund().subtract(sub.get(4).getThsCloseWFund()), BigDecimal.ZERO).abs();
                BigDecimal DU = X2.add(sub.get(4).getRsi6diefu().multiply(new BigDecimal(5))).divide(new BigDecimal(6), 4, RoundingMode.HALF_UP);
                BigDecimal RSI = getRSI(AU, DU);
                sub.get(5).setRsi6(RSI);
                sub.get(5).setRsi6zhangfu(AU);
                sub.get(5).setRsi6diefu(DU);
            }
        }
    }

    // A上涨  DU下跌
    private BigDecimal getRSI(BigDecimal AU, BigDecimal DU) {
        if (AU.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.ZERO;
        } else if (DU.compareTo(BigDecimal.ZERO) == 0) {
            return new BigDecimal("100");
        }
        try {
            return new BigDecimal("100").subtract(
                    new BigDecimal("100").divide(new BigDecimal("1").add(AU.divide(DU, 4, RoundingMode.HALF_UP)), 4, RoundingMode.HALF_UP)
            );
        } catch (Exception e) {
            e.printStackTrace();
        }
        return BigDecimal.ZERO;
    }

    private List<GWeekPrice> copyList(JSONArray list) {
        // 最新一周的数据
        List<GWeekPrice> returnList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            // 当周的数据
            JSONArray lastData = (JSONArray) list.get(i);
            // 一周前数据
            JSONArray oneWeekAgo = null;
            if (i > 1) {
                oneWeekAgo = (JSONArray) list.get(i - 1);
            }

            GWeekPrice build = GWeekPrice.builder()
                    .thscode("512890.SH")
                    .time(lastData.getDate(0))
                    .thsOpenWFund(lastData.getBigDecimal(1))
                    .thsCloseWFund(lastData.getBigDecimal(2))
                    .thsHighWFund(lastData.getBigDecimal(3))
                    .thsLowWFund(lastData.getBigDecimal(4))
                    .thsChgWFund(BigDecimal.ZERO)
                    .thsChgRatioWFund(BigDecimal.ZERO)
                    .build();
            if (oneWeekAgo != null) {
                build.setThsChgWFund(lastData.getBigDecimal(2).subtract(oneWeekAgo.getBigDecimal(2)));
                build.setThsChgRatioWFund(lastData.getBigDecimal(2).subtract(oneWeekAgo.getBigDecimal(2))
                        .divide(oneWeekAgo.getBigDecimal(2), 6, RoundingMode.HALF_UP)
                        .multiply(new BigDecimal("100")));
            }
            returnList.add(build);
        }

        return returnList;
    }


    private BigDecimal max(BigDecimal a, BigDecimal b) {
        if (a.compareTo(b) > 0) {
            return a;
        } else {
            return b;
        }
    }

    private BigDecimal min(BigDecimal a, BigDecimal b) {
        if (a.compareTo(b) > 0) {
            return b;
        } else {
            return a;
        }
    }


}
